package com.aiyige.city.util;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.text.TextUtils;

import com.aiyige.BuildConfig;
import com.aiyige.MyApp;
import com.aiyige.city.model.City;
import com.aiyige.city.service.UpdateCityService;
import com.aiyige.configs.MyConfig;
import com.aiyige.utils.AppUtils;
import com.aiyige.utils.ListUtil;
import com.aiyige.utils.MD5Util;
import com.aiyige.utils.PreferenceUtil;
import com.alibaba.fastjson.JSON;
import com.vondear.rxtools.RxFileTool;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import okhttp3.ResponseBody;
import retrofit2.Response;
import timber.log.Timber;

/**
 * Created by zhuyakun on 2018/1/23.
 */

public class CityUtil {
    public static final String CITY_FILE_DIR = MyConfig.AIYIGE_ROOT_DIR;
    public static final String CITY_FILE_PATH = CITY_FILE_DIR + BuildConfig.cityJson;
    public static final String PREF_KEY_LAST_UPDATE_CITY_TIMESTAMP = "com.aiyige.pref.city.PREF_KEY_LAST_UPDATE_CITY_TIMESTAMP";
    private static final String PREF_KEY_VERSION_NAME = "com.aiyige.pref.city.PREF_KEY_VERSION_NAME";//city模块专用，不要用在别处

    private static List<City> cityList = new LinkedList<>();
    private static Lock mutex = new ReentrantLock();
    private static Lock copyMutex = new ReentrantLock();
    public static final long UPDATE_CITY_INTERVAL_MS = 24 * 60 * 60 * 1000;
    public static final long RANDOM_DELAY_LOW_BOUND_MS = 5 * 60 * 1000;
    public static final long RANDOM_DELAY_RANGE_MS = 5 * 6 * 1000;

    public static List<City> getCityList() {
        List<City> list;
        mutex.lock();
        list = cityList;
        mutex.unlock();
        return list;
    }

    public static void copyCityFromServer(Response<ResponseBody> response) throws Exception {
        Exception capturedException = null;
        copyMutex.lock();
        RxFileTool.createOrExistsDir(CITY_FILE_DIR);
        InputStream in = null;
        try {
            in = response.body().byteStream();
            RxFileTool.copyFile(in, new File(CITY_FILE_PATH));
        } catch (Exception e) {
            capturedException = e;
        } finally {
            try {
                in.close();
            } catch (Exception e) {

            }
        }
        copyMutex.unlock();
        if (capturedException != null) {
            throw capturedException;
        }
    }

    public static void copyCityFromAsset() throws Exception {
        Exception capturedException = null;
        copyMutex.lock();
        if (!RxFileTool.isFileExists(CITY_FILE_PATH) || checkAppNewInstallOrUpgrade()) {
            makeUpdateCityIsNeverUpdate();
            RxFileTool.createOrExistsDir(CITY_FILE_DIR);
            InputStream in = null;
            try {
                in = MyApp.getAppContext().getAssets().open("city.json");
                RxFileTool.copyFile(in, new File(CITY_FILE_PATH));
            } catch (Exception e) {
                capturedException = e;
            } finally {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }

        }
        copyMutex.unlock();
        if (capturedException != null) {
            throw capturedException;
        }
    }

    public static String getCityFileHash() {
        if (RxFileTool.isFileExists(CITY_FILE_PATH)) {
            return MD5Util.calculateFileMD5(new File(CITY_FILE_PATH));
        } else {
            return "";
        }
    }

    public static void populateCityList(boolean forceRefresh) {
        if (!forceRefresh) {
            copyMutex.lock();
            mutex.lock();
            if (ListUtil.isEmpty(cityList)) {
                mutex.unlock();
                copyMutex.unlock();
            } else {
                mutex.unlock();
                copyMutex.unlock();
                return;
            }
        }
        copyMutex.lock();
        City[] cityArray = null;
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(CITY_FILE_PATH);
            cityArray = JSON.parseObject(inputStream, City[].class);
        } catch (Exception e) {

        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {

            }
        }
        copyMutex.unlock();
        if (cityArray == null || cityArray.length == 0) {
            return;
        }
        mutex.lock();
        cityList.clear();
        for (City city : cityArray) {
            cityList.add(city);
        }
        mutex.unlock();
    }

    public static void populateCityList() {
        populateCityList(true);
    }

    public static void updateCityNow() {
        UpdateCityService.updateCity(MyApp.getAppContext());
    }

    public static void updateCityWithRandomDelay() {
        Random random = new Random();
        Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                updateCityNow();
            }
        }, RANDOM_DELAY_LOW_BOUND_MS + (long) (random.nextFloat() * RANDOM_DELAY_RANGE_MS));
    }

    public static void updateCityIfTooOld() {
        if (System.currentTimeMillis() - PreferenceUtil.getLong(PREF_KEY_LAST_UPDATE_CITY_TIMESTAMP, 0) > UPDATE_CITY_INTERVAL_MS) {
            PreferenceUtil.putLong(PREF_KEY_LAST_UPDATE_CITY_TIMESTAMP, System.currentTimeMillis());
            Timber.e("updateCityIfTooOld:detect city too old and will update immediately...");
            updateCityWithRandomDelay();
        }
    }

    public static void makeUpdateCityIsNeverUpdate() {
        PreferenceUtil.putLong(PREF_KEY_LAST_UPDATE_CITY_TIMESTAMP, 0);
    }


    public static boolean checkAppNewInstallOrUpgrade() {
        String prefVersionName = PreferenceUtil.getString(PREF_KEY_VERSION_NAME, "");
        String currentVersionName = AppUtils.getAppVersionName();
        if (TextUtils.isEmpty(currentVersionName) || !currentVersionName.equals(prefVersionName)) {
            PreferenceUtil.putString(PREF_KEY_VERSION_NAME, currentVersionName);
            return true;
        } else {
            return false;
        }
    }


    public static void installUpdateAlarm() {
        Intent intent = new Intent(MyApp.getAppContext(), UpdateCityService.class);
        PendingIntent pintent = PendingIntent.getService(MyApp.getAppContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarm = (AlarmManager) MyApp.getAppContext().getSystemService(Context.ALARM_SERVICE);
        if (alarm != null) {
            alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + UPDATE_CITY_INTERVAL_MS, UPDATE_CITY_INTERVAL_MS, pintent);
        }
    }

}
